package com.example.huangliting.experimentalarrangementsystem.view;

import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
import android.widget.AdapterView;

import com.example.huangliting.experimentalarrangementsystem.R;
import com.example.huangliting.experimentalarrangementsystem.adapter.KBCalendarAdapter;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

public class KBCalendar extends View {
    private String TAG = "KBCalendar";

    private TwoWayView mListView;
    private KBCalendarAdapter mCalendarAdapter;
    private ArrayList<Date> mListDays;

    //Interface events
    private IKBAgendaEvent iAgendaDateSelect;

    // RootView
    private View rootViewParent;

    // Number of Row Show on Screen
    private int numberOfRowOnScreen = 5;

    // sp
    private int weekSize = 13;
    private int monthSize = 13;
    private int dayNumberSize = 30;

    public int normalColor = 0xFF030303;
    public int outBoundColor = 0xFFaaaaaa;
    public int selectColor = 0xFFff8403;

    private SimpleDateFormat dateFormat;
    private String formatDate;

    // is first time list view load completed
    private boolean isFirstTime = true;

    // The width of each child
    private int objWidth = 80;

    private float density;

    Date dateStartCalendar = null;
    Date dateEndCalendar = null;

    public KBCalendar(Context context, Handler handler) {
        super(context);
        init();
    }

    public KBCalendar(Context context, IKBAgendaEvent iAgendaDateSelect) {
        super(context);
        this.iAgendaDateSelect = iAgendaDateSelect;
        init();
    }

    public KBCalendar(Context context, IKBAgendaEvent iAgendaDateSelect, View rootViewParent) {
        super(context);
        this.iAgendaDateSelect = iAgendaDateSelect;
        this.rootViewParent = rootViewParent;
        init();
    }

    // set list data, add some data in the head and foot, show it blank
    public void setListDays(ArrayList<Date> listDays) {
        if (listDays == null) {
            return;
        }
        mListDays.clear();
        dateStartCalendar = listDays.get(0);
        dateEndCalendar = listDays.get(listDays.size() - 1);

        GregorianCalendar calendar = new GregorianCalendar();
        calendar.setTime(dateStartCalendar);
        calendar.add(Calendar.DATE, -numberOfRowOnScreen / 2);
        Date dateStartBefore = calendar.getTime();
        for (Date date = dateStartBefore; !date.equals(dateStartCalendar); ) {
            calendar.setTime(date);
            mListDays.add(date);
            calendar.add(Calendar.DATE, 1);
            date = calendar.getTime();
        }

        mListDays.addAll(listDays);

        calendar.setTime(dateEndCalendar);
        calendar.add(Calendar.DATE, numberOfRowOnScreen / 2);
        Date dateEndAfter = calendar.getTime();
        for (Date date = dateEndCalendar; date.before(dateEndAfter); ) {
            calendar.setTime(date);
            calendar.add(Calendar.DATE, 1);
            date = calendar.getTime();
            mListDays.add(date);
        }
    }

    private void init() {
        final Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        density = getContext().getResources().getDisplayMetrics().density;
        objWidth = (int) (objWidth * density);
        final int displayWidth = display.getWidth();
        int childCount = displayWidth / objWidth;
        // Make sure to round up
        if (displayWidth % objWidth != 0) {
            childCount++;
        }
        // Now make sure we have an odd number of children
        if (childCount % 2 == 0) {
            childCount++;
        }
        numberOfRowOnScreen = childCount;

        formatDate = "yyyy-MM-dd";

        dateFormat = new SimpleDateFormat(formatDate);
        mListDays = new ArrayList<Date>();
        initListDays();
    }

    public void initListDays() {
        ArrayList<Date> listDays = new ArrayList<Date>();;
        GregorianCalendar calendar = new GregorianCalendar();
        calendar.add(Calendar.MONTH, -1);
        Date dateStartBefore = calendar.getTime();
        calendar.add(Calendar.MONTH, 2);
        Date dateEndBefore = calendar.getTime();
        for (Date date = dateStartBefore; !date.equals(dateEndBefore); ) {
            calendar.setTime(date);
            listDays.add(date);
            calendar.add(Calendar.DATE, 1);
            date = calendar.getTime();
        }
        setListDays(listDays);
    }

    /* Init KBCalendar View ; This method have to be call imperatively */
    public void loadKBCalendar(View view) {
        View rootView;
        if (rootViewParent != null) {
            rootView = rootViewParent;
        } else {
            //rootView = ((Activity) getContext()).getWindow().getDecorView().findViewById(android.R.id.content);
            rootView = view;
        }

        mListView = (TwoWayView) rootView.findViewById(R.id.list);
        mListView.setHorizontalScrollBarEnabled(false);

        mCalendarAdapter = new KBCalendarAdapter(this, getContext(), mListDays, numberOfRowOnScreen);
        mListView.setAdapter(mCalendarAdapter);
        mListView.setOnScrollListener(new TwoWayView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(TwoWayView view, int scrollState) {
                if (scrollState == 0) {
                    //On scroll end, the dateSelect event is call
                    //and agenda is center to the good item
                    int position = mCalendarAdapter.getPositionOfCenterItem();
                    centerToPosition(position);
                    if (iAgendaDateSelect != null)
                        iAgendaDateSelect.onDateSelect(mListDays.get(position));
                }
            }

            @Override
            public void onScroll(TwoWayView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                //On Scroll, agenda is refresh to update background colors
                mCalendarAdapter.notifyDataSetChanged();
                iAgendaDateSelect.onListScroll(getCurrentDate());
            }
        });
        mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View child, int position,
                                    long id) {
                //On item Click, the dateSelect event is call
                //and agenda is center to the good item
//                centerToPosition(position);
                centerToClickPosition(position);
                if (iAgendaDateSelect != null)
                    iAgendaDateSelect.onDateSelect(mListDays.get(position));
            }
        });

        //view finish load callback
        mListView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                // TODO Auto-generated method stub
                if (isFirstTime) {
                    goToday();
                    isFirstTime = false;
                }
            }
        });
    }

    /* Center the listView to today */
    public void goToday() {
        centerToDate(new Date());
    }

    /* Center the listView to the date*/
    public void centerToDate(Date dateCenter) {
        centerToPosition(positionOfDate(dateCenter));
    }

    /* Set the start date of the calendar */
    public void setDateStartCalendar(Date dateStartCalendar) {
        this.dateStartCalendar = dateStartCalendar;
    }

    public Date getDateStartCalendar() {
        return dateStartCalendar;
    }


    /* Set the date end of the calendar */
    public void setDateEndCalendar(Date dateEndCalendar) {
        this.dateEndCalendar = dateEndCalendar;
    }

    public Date getDateEndCalendar() {
        return dateEndCalendar;
    }

    public Date getToday() {
        return new Date();
    }

    /* Set the number of row that appears on screen */
    public void setNumberOfRowOnScreen(int numberOfRowOnScreen) {
        this.numberOfRowOnScreen = numberOfRowOnScreen;
    }

    /* Return the current selected date */
    public Date getCurrentDate() {
        return mListDays.get(getPositionOfCenterItem());
    }

    /* Getters and setters for Format, Font Size and Colors*/
    public int getWeekSize() {
        return weekSize;
    }

    public void setWeekSize(int weekSize) {
        this.weekSize = weekSize;
    }

    public int getMonthSize() {
        return monthSize;
    }

    public void setMonthSize(int monthSize) {
        this.monthSize = monthSize;
    }

    public int getDayNumberSize() {
        return dayNumberSize;
    }

    public void setDayNumberSize(int dayNumberSize) {
        this.dayNumberSize = dayNumberSize;
    }

    /* Return position of date in listView ; Return -1 if date not exist */
    private int positionOfDate(Date date) {
        int position = -1;
        for (int i = 0; i < mListDays.size(); i++) {
            if (isDatesDaysEquals(date, mListDays.get(i))) {
                position = i;
            }
        }
        return position;
    }

    /* Return true if dates are equals */
    public boolean isDatesDaysEquals(Date date1, Date date2) {
        if (dateFormat.format(date1).equals(dateFormat.format(date2))) return true;
        else return false;
    }

    /* Center KBAdapter to an item with its position */
    private void centerToPosition(int position) {
        CenterToPositionTask centerTask = new CenterToPositionTask();
        centerTask.position = position;
        centerTask.execute();
    }

    private void centerToClickPosition(int position) {
        final int count = mCalendarAdapter.getPositionOfCenterItem() - position;
        final int diff = count * mCalendarAdapter.widthCell;

        final View child = mListView.getChildAt(0);
        final int childLeft = child.getLeft();
        Log.e(TAG, "mListView.mScroller.getCurrX():" + mListView.mScroller.getCurrX());
        mListView.mLastTouchPos = mListView.mScroller.getCurrX();
        mListView.mScroller.startScroll(mListView.mScroller.getCurrX(), 0, diff, 0, Math.abs(500 * count));
        mListView.postInvalidate();
    }

    /* Return position of selected date on center of screen*/
    private int getPositionOfCenterItem() {
        return mListView.getFirstVisiblePosition() + numberOfRowOnScreen / 2;
    }

    private class CenterToPositionTask extends AsyncTask<Void, Void, String[]> {
        int position;

        protected void onPreExecute() {

            if (position != -1) {
                mListView.post(new Runnable() {
                    @Override
                    public void run() {
                        //Selection item is the firstItemVisible
                        //So the selected item is set to the position - the number of row /2
                        int shiftCells = numberOfRowOnScreen / 2;
                        if (position - shiftCells >= 0) {
                            mListView.setSelection(position - shiftCells);
                        } else {
                            mListView.setSelection(0);
                        }
                    }
                });
            }
        }

        @Override
        protected String[] doInBackground(Void... params) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String[] result) {
            super.onPostExecute(result);

            //Refresh the adapter to draw background cells color
            mCalendarAdapter.notifyDataSetChanged();
        }
    }

    private class InitTask extends AsyncTask<Void, Void, String[]> {
        protected void onPreExecute() {
        }

        @Override
        protected String[] doInBackground(Void... params) {
            return null;
        }

        @Override
        protected void onPostExecute(String[] result) {
            super.onPostExecute(result);
            goToday();
        }
    }

    public void setSelectColor(int selectColor) {
        this.selectColor = selectColor;
    }

    public void setOutBoundColor(int outBoundColor) {
        this.outBoundColor = outBoundColor;
    }

    public void setNormalColor(int normalColor) {
        this.normalColor = normalColor;
    }

    public interface IKBAgendaEvent {

        public void onDateSelect(Date date);

        public void onListScroll(Date date);

    }
}